package com.gitee.wsl.serialization.id

import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.builtins.serializer
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlin.jvm.JvmName
import kotlin.jvm.JvmStatic

/**
 * 一个通过 [64位无符号整型 (unsigned long)][ULong] 作为ID值的 [NumericalID] 实现。
 *
 * @property value 源值。
 * 对于不支持直接操作无符号类型的目标来说，可能需要使用额外手段操作。
 *
 * 例如 Java 中，需要借助 `java.lang.Long` 中与无符号相关的API进行操作，
 * 比如 `java.lang.Long.toUnsignedString`。
 */
@Serializable(with = ULongID.Serializer::class)
public class ULongID private constructor(@get:JvmName("getValue") public val value: ULong) : UnsignedNumericID() {
    override fun toDouble(): Double = value.toDouble()
    override fun toFloat(): Float = value.toFloat()
    override fun toLong(): Long = value.toLong()
    override fun toULong(): ULong = value
    override fun toInt(): Int = value.toInt()
    override fun toShort(): Short = value.toShort()
    override fun toByte(): Byte = value.toByte()
    override fun toString(): String = value.toString()
    override fun hashCode(): Int = value.hashCode()

    override fun equals(other: Any?): Boolean = idCommonEq(other) {
        when (it) {
            is NumericalID -> compareNumber(it) == 0
            else -> value.toString() == it.toString()
        }
    }

    override fun equalsExact(other: Any?): Boolean = idExactEq(other) {
        value == it.value
    }

    override fun compareNumber(target: NumericalID): Int = compareULongID(target)

    override fun copy(): ULongID = ULongID(value)

    public companion object {
        /**
         * 将一个 [ULong] 转化为 [ULongID]。
         */
        @get:JvmStatic
        @get:JvmName("valueOf")
        public val ULong.ID: ULongID
            get() = ULongID(this)
    }

    internal object Serializer : KSerializer<ULongID> {
        override val descriptor: SerialDescriptor =
            PrimitiveSerialDescriptor("ULongID", PrimitiveKind.LONG)

        override fun deserialize(decoder: Decoder): ULongID = ULong.serializer().deserialize(decoder).ID

        override fun serialize(encoder: Encoder, value: ULongID) {
            ULong.serializer().serialize(encoder, value.value)
        }
    }
}